<!--
 @description 省市区选择弹窗
 @fileName index.vue
 @author zengqiongying
 @created 2022/10/30 13:04:30
-->
<template>
  <Popup
    v-model="popShow"
    position="bottom"
    :title="pageTitle"
    :show-cancel-button="false"
    :show-confirm-button="requiredLevle < 4"
    @confirm="handleSubmit"
  >
    <div class="select-list">
      <div class="option selected-title">
        <span v-for="(item, i) in selName" :key="i" :class="['tab', { empty: level === i }]" @click="handleClickTab(i)">
          <span v-if="i <= level || !!selCode[level]">{{ i === level ? placeholder[i] : item }}</span>
        </span>
      </div>
      <div class="list-scroll">
        <Scroll vertical height="100%">
          <div v-for="(item, i) in list" :key="i" class="option" @click="handleClick(item)">
            <span class="name">{{ item.name }}</span>
            <span class="icon" :class="{ checked: item[fieldKey] === selCode[level] }"></span>
          </div>
        </Scroll>
      </div>
    </div>
  </Popup>
</template>

<script lang="ts">
  import Popup from '@/components/Popup/index.vue'
  import Scroll from '@/components/Scroll/index.vue'
  import { getProvinces, getAreaList } from '@/apis/dataDict'
  import { computed, reactive, toRefs, watch, defineComponent, getCurrentInstance } from 'vue'
  import type { PropType } from 'vue'

  interface objInter {
    // formData: any
    [key: string]: any
    level: number
  }

  export default defineComponent({
    name: 'PopArea',
    components: { Popup, Scroll },
    props: {
      show: {
        type: Boolean,
        default: false
      },
      requiredLevle: {
        type: Number,
        default: 3
      }, // 必选层级
      modelValue: {
        // type: [String, Object],
        type: [String, Object] as PropType<string | any>,
        default: ''
      }, // 选中的值
      fieldKey: {
        type: String,
        default: 'code'
      } // 地区主键字段键名：code 地区编码 ， id 地区ID
    },
    setup(props, ctx) {
      const { proxy }: any = getCurrentInstance()

      const datas = reactive<objInter>({
        formData: {
          provinceId: '',
          province: '',
          provinceCode: '',
          cityId: '',
          city: '',
          cityCode: '',
          districtId: '',
          district: '',
          districtCode: '',
          townId: '',
          town: '',
          townCode: ''
        },
        placeholder: ['省份/地区', '城市', '区/县', '街道/镇'],
        level: 0,
        provinceList: [],
        cityList: [],
        countyList: [],
        streetList: []
      })
      const popShow = computed({
        set(val) {
          ctx.emit('update:show', val)
        },
        get() {
          return props.show
        }
      })
      const selName = computed(() => {
        const { province, city, district, town } = datas.formData
        return [province, city, district, town]
      })
      const pageTitle = computed(() => {
        if (selName.value.length > 0) {
          return selName.value.join(' ')
        }
        return '选择地区'
      })

      const list = computed(() => {
        if (datas.level === 0) {
          return datas.provinceList
        } else if (datas.level === 1) {
          return datas.cityList
        } else if (datas.level === 2) {
          return datas.countyList
        } else if (datas.level === 3) {
          return datas.streetList
        }
        return []
      })

      const selCode = computed(() => {
        const { provinceId, provinceCode, cityId, cityCode, districtId, districtCode, townId, townCode } =
          datas.formData
        if (props.fieldKey === 'code') {
          return [provinceCode, cityCode, districtCode, townCode]
        }
        return [provinceId, cityId, districtId, townId]
      })

      // 获取所有省份数据
      const initProvinceData = async () => {
        // 获取省
        await getProvinces().then((res) => {
          const list: any = res.data || []
          datas.provinceList = list
        })
      }

      /**
       * 获取市、区、街道数据
       * @param {Number} level  等级：1 市 ， 2 区县 ， 3 街道/镇
       * @param {string} parentCode  省编码
       * @param {string} parentCode  省编码
       * @param {string} parentId  省Id
       * @returns {Array} 市列数据
       */
      const getCityData = async (level: number, parentCode: string, parentId: string) => {
        let pId = parentId || ''
        const listName = ['provinceList', 'cityList', 'countyList', 'streetList']
        let checkCode = false // 当前查询参数是否为Code（若长度为20为id,反之code）
        if (props.fieldKey === 'code') {
          // 关键字为Code，通过code查找id进行子级查询
          checkCode = parentCode.length !== 20
          if (!checkCode) {
            pId = parentCode
          }
        } else {
          // 关键字为id,判断当前参数是否为id
          checkCode = parentId.length !== 20
        }

        if (checkCode) {
          const data: any = datas
          const parentList = data[listName[level - 1]]
          const o = parentList.filter((v: any) => v.code === parentCode)
          pId = o && o.length ? o[0].id : '' // 父级ID
        }

        let resultData: any = []
        if (pId) {
          await getAreaList(pId).then((res) => {
            resultData = res.data || []
          })
        }
        datas[listName[level]] = resultData
      }

      const handleClickTab = (level: number) => {
        datas.level = level
      }

      const initFormData = async () => {
        await initProvinceData()

        datas.level = 0
        const tmpObj: any = {}
        if (props.modelValue && (props.modelValue.provinceCode || props.modelValue.provinceId)) {
          if (props.modelValue.provinceCode || props.modelValue.provinceId) {
            if (props.fieldKey === 'id') {
              if (!props.modelValue.provinceCode) {
                const obj: any = datas.provinceList.find((v: any) => v.id === props.modelValue.provinceId)
                tmpObj.provinceCode = obj.code
              }
            } else {
              if (!props.modelValue.provinceId) {
                const obj: any = datas.provinceList.find((v: any) => v.code === props.modelValue.provinceCode)
                tmpObj.provinceId = obj.id
              }
            }
            await getCityData(1, props.modelValue.provinceCode, props.modelValue.provinceId)
            datas.level = 1
          }
          if (props.modelValue.cityCode || props.modelValue.cityId) {
            if (props.fieldKey === 'id') {
              if (!props.modelValue.cityCode) {
                const obj: any = datas.cityList.find((v: any) => v.id === props.modelValue.cityId)
                tmpObj.cityCode = obj.code
              }
            } else {
              if (!props.modelValue.cityId) {
                const obj: any = datas.cityList.find((v: any) => v.code === props.modelValue.cityCode)
                tmpObj.cityId = obj.id
              }
            }

            await getCityData(2, props.modelValue.cityCode, props.modelValue.cityId)
            datas.level = 2
          }
          if (props.modelValue.districtCode || props.modelValue.districtId) {
            if (props.fieldKey === 'id') {
              if (!props.modelValue.districtCode) {
                const obj: any = datas.countyList.find((v: any) => v.id === props.modelValue.districtId)
                tmpObj.districtCode = obj.code
              }
            } else {
              if (!props.modelValue.districtId) {
                const obj: any = datas.countyList.find((v: any) => v.code === props.modelValue.districtCode)
                tmpObj.districtId = obj.id
              }
            }
            await getCityData(3, props.modelValue.districtCode, props.modelValue.districtId)
            datas.level = 3
          }
          if (datas.streetList.length > 0 && (props.modelValue.townId || props.modelValue.townCode)) {
            if (props.fieldKey === 'id') {
              if (!props.modelValue.townCode) {
                const obj: any = datas.streetList.find((v: any) => v.id === props.modelValue.townId)
                tmpObj.townCode = obj.code
              }
            } else {
              if (!props.modelValue.townId) {
                const obj: any = datas.streetList.find((v: any) => v.code === props.modelValue.townCode)
                tmpObj.townId = obj.id
              }
            }
          }
        }
        if (Object.keys(tmpObj).length > 0) {
          ctx.emit('input', { ...props.modelValue, ...tmpObj })
        }

        const formData: any = datas.formData
        for (const key in formData) {
          const value = props.modelValue[key] || tmpObj[key] || ''
          formData[key] = value
          datas.formData = formData
        }
      }

      const handleClick = async (data: any) => {
        const { name, code, id } = data
        if (datas.level === 0) {
          const flag =
            props.fieldKey === 'code' ? datas.formData.provinceCode === code : datas.formData.provinceId === id
          if (flag) {
            datas.level = 1
            return
          }
          clearData([
            'cityId',
            'city',
            'cityCode',
            'districtId',
            'district',
            'districtCode',
            'townId',
            'town',
            'townCode'
          ])
          datas.formData.province = name
          datas.formData.provinceId = id
          datas.formData.provinceCode = code
          await getCityData(1, code, id)
          datas.level = 1
        } else if (datas.level === 1) {
          const flag = props.fieldKey === 'code' ? datas.formData.cityCode === code : datas.formData.cityId === id
          if (flag) {
            datas.level = 2
            return
          }
          clearData(['districtId', 'district', 'districtCode', 'townId', 'town', 'townCode'])
          datas.formData.city = name
          datas.formData.cityId = id
          datas.formData.cityCode = code
          await getCityData(2, code, id)
          datas.level = 2
        } else if (datas.level === 2) {
          const flag =
            props.fieldKey === 'code' ? datas.formData.districtCode === code : datas.formData.districtId === id
          if (flag) {
            if (datas.streetList.length > 0) {
              datas.level = 3
            }
            return
          }
          clearData(['townId', 'town', 'townCode'])
          datas.formData.district = name
          datas.formData.districtId = id
          datas.formData.districtCode = code
          await getCityData(3, code, id)
          if (datas.streetList.length === 0) {
            handleSubmit()
          } else {
            datas.level = 3
          }
        } else if (datas.level === 3) {
          // if (this.formData.townCode === code) return
          datas.formData.town = name
          datas.formData.townId = id
          datas.formData.townCode = code
          handleSubmit()
        }
      }

      const clearData = (fields: any) => {
        const formData: any = datas.formData

        if (fields.length === 0) {
          for (const key in formData) {
            formData[key] = ''
            // this.$set(datas.formData, key, '')
          }
        } else {
          fields.forEach((v: any) => {
            formData[v] = ''
            // this.$set(datas.formData, v, '')
          })
        }
        datas.formData = formData
      }

      const handleSubmit = () => {
        ctx.emit('input', datas.formData)

        const districtFlag =
          props.fieldKey === 'code' ? datas.formData.districtCode === '' : datas.formData.districtId === ''
        if (districtFlag) {
          proxy.$toast('请选择省市区县')
          return
        }
        if (props.requiredLevle === 4) {
          if (datas.streetList.length > 0) {
            const streetFlag = props.fieldKey === 'code' ? datas.formData.townCode === '' : datas.formData.townId === ''
            if (streetFlag) {
              proxy.$toast('请选择街道')
              return
            }
          }
        }
        const params: any = {}
        for (const [k, v] of Object.entries(datas.formData)) {
          params[k] = v
        }
        ctx.emit('input', params)
        ctx.emit('change', params)
        popShow.value = false
      }

      watch(
        () => props.modelValue,
        (val) => {
          initFormData()
        },
        {
          deep: true,
          immediate: true
        }
      )

      return {
        ...toRefs(datas),
        popShow,
        pageTitle,
        selName,
        list,
        selCode,
        handleClickTab,
        handleClick,
        handleSubmit
      }
    }
  })
</script>
<style lang="less" scoped>
  .select-list {
    padding: 0 16px;
    border-radius: 8px;
    // background: rgba(239, 242, 247, .6);
    overflow: hidden;
    .option {
      height: 55px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 1px solid rgba(0, 0, 0, 0.1);
      &:last-child {
        border-bottom: 0;
      }
    }
    .name {
      font-size: 16px;
      color: #3c4458;
    }
    .icon {
      width: 20px;
      height: 14px;
      margin-left: 10px;
      &.checked {
        background: url(~@/assets/images/icon-yes.png);
        background-size: 20px 14px;
      }
    }
  }
  .selected-title {
    justify-content: flex-start !important;
    font-size: 16px;
    color: #3c4458;
    .tab {
      padding-right: 10px;
      // width: 25%;
      height: 20px;
      box-sizing: border-box;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      overflow: hidden;
      -webkit-line-clamp: 1;
      &:last-child {
        padding-right: 0;
      }
    }
    .empty {
      color: #b5b7c4;
    }
  }
  .list-scroll {
    height: 60vh;
  }
</style>
